#!/bin/sh

e2e_test_install() {
  NODE_LABEL_KEY="$(random_string)"
  NODE_LABEL_VALUE="$(random_string)"

  BACKUPCONF="backupconf"

  kubectl create namespace "$CLUSTER_NAMESPACE"
  kubectl create secret generic -n "$CLUSTER_NAMESPACE" "test" \
     --from-literal=accesskey=test --from-literal=secretkey=test

  create_or_replace_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" 1 \
    --set cluster.configurations.backups.sgObjectStorage="$BACKUPCONF" \
    --set-string "cluster.pods.scheduling.nodeSelector.$NODE_LABEL_KEY=$NODE_LABEL_VALUE" \
    --set configurations.objectstorage.create=true \
    --set-string configurations.objectstorage.s3Compatible.bucket=test \
    --set-string configurations.objectstorage.s3Compatible.awsCredentials.secretKeySelectors.accessKeyId.name=test \
    --set-string configurations.objectstorage.s3Compatible.awsCredentials.secretKeySelectors.accessKeyId.key=accesskey \
    --set-string configurations.objectstorage.s3Compatible.awsCredentials.secretKeySelectors.secretAccessKey.name=test \
    --set-string configurations.objectstorage.s3Compatible.awsCredentials.secretKeySelectors.secretAccessKey.key=secretkey \
    --set-string cluster.configurations.backups.cronSchedule='0 5 31 2 *'

  deploy_curl_pod "$CLUSTER_NAMESPACE"

  wait_pods_running "$CLUSTER_NAMESPACE" 1

  BACKUP_NAME="$(get_sgbackup_name "${CLUSTER_NAME}-0-$(shuf -i 0-65535 -n 1)")"

    cat << EOF | kubectl create -f -
  apiVersion: stackgres.io/v1
  kind: SGBackup
  metadata:
    namespace: "$CLUSTER_NAMESPACE"
    name: "$BACKUP_NAME"
  spec:
    sgCluster: "$CLUSTER_NAME"
    managedLifecycle: false
EOF

  OPERATOR_BACKUP_CR="$(kubectl get sgbackups.stackgres.io -n "$CLUSTER_NAMESPACE" "$BACKUP_NAME" -o json \
    | jq 'del(.metadata.creationTimestamp) | del(.metadata.generation)
      | del(.metadata.resourceVersion) | del(.metadata.selfLink) | del(.metadata.uid)' )"

  echo_raw "$OPERATOR_BACKUP_CR" > "$LOG_PATH/stackgres-backup-cr.json"

  OPERATOR_BACKUP="$(cat "$LOG_PATH/stackgres-backup-cr.json" \
    | jq 'del(.apiVersion) | del(.kind) | del(.status) | del(.metadata.annotations)' )"

  echo_raw "$OPERATOR_BACKUP" > "$LOG_PATH/stackgres-backup.json"
}

e2e_test() {
  run_test "Check that a created backup can be accessed directly through the API" check_backup_directly

  run_test "Check that a created backup is included in the response" check_backup_in_list

  run_test "Check that a backup was removed after its deletion in the API" check_backup_removed

  run_test "Check backup is created with the API and is visible in the API" test_api_created_backup_is_visible

  run_test "Check backup is updated with the API are reflected in the API" test_api_updated_backup_is_visible

  run_test "Check backup is deleted with the API are reflected in the API" test_api_delete_backup_is_visible

  run_test "Constraint violations should be detected" test_constraint_violation_api_error

  run_test "User with wrong credentials should not be authenticated" test_authentication_api_error
}

check_backup_in_list() {
  if run_curl -r "stackgres/sgbackups" \
    | jq -r ".[] | select ( .metadata.namespace == \"$CLUSTER_NAMESPACE\"
      and .metadata.name == \"$BACKUP_NAME\") | .metadata.name" \
    | grep -q "^$BACKUP_NAME$"
  then
    echo "Backup $BACKUP_NAME included in json response"
    return 0
  else
    echo "Backup $BACKUP_NAME not included in json response"
    return 1
  fi
}

get_backup_http_status() {
  run_curl -r "stackgres/namespaces/$CLUSTER_NAMESPACE/sgbackups/$BACKUP_NAME" \
    -e "-LI -o /dev/null -w %{http_code}"
}

check_backup_directly() {
  local HTTP_STATUS

  HTTP_STATUS="$(get_backup_http_status)"

  if [ "$HTTP_STATUS" -eq "200" ]
  then
    echo "Backup $BACKUP_NAME was found by the api"
    return 0
  else
    echo "Backup $BACKUP_NAME was not found by the api"
    return 1
  fi
}

remove_backup_cr_if_exists() {
  if kubectl get sgbackups.stackgres.io -n "$CLUSTER_NAMESPACE" "$BACKUP_NAME"
  then
    kubectl delete sgbackups.stackgres.io -n "$CLUSTER_NAMESPACE" "$BACKUP_NAME"

    wait_until eval '! kubectl get sgbackups.stackgres.io -n "$CLUSTER_NAMESPACE" "$BACKUP_NAME"'
  fi
}

check_backup_removed() {
  local HTTP_STATUS

  remove_backup_cr_if_exists

  if run_curl -r "stackgres/sgbackups" \
    | jq -r ".[] | select ( .metadata.namespace == \"$CLUSTER_NAMESPACE\"
      and .metadata.name == \"$BACKUP_NAME\") | .metadata.name" \
    | grep -q "^$BACKUP_NAME$"
  then
    echo "Backup $BACKUP_NAME wasn't removed from cache"
    return 1
  else
    echo "Backup $BACKUP_NAME was removed from cache"
    return 0
  fi

  HTTP_STATUS="$(run_curl -r "stackgres/namespaces/$CLUSTER_NAMESPACE/sgbackups/$BACKUP_NAME" \
    -e "-LI -o /dev/null -w %{http_code}")"

  if [ "$HTTP_STATUS" -eq "404" ]
  then
    echo "Backup $BACKUP_NAME was not found by the api"
    return 0
  else
    echo "Backup $BACKUP_NAME was found by the api"
    return 1
  fi
}

create_backup_with_api() {
  local HTTP_STATUS

  remove_backup_cr_if_exists

  HTTP_STATUS="$(run_curl -r "stackgres/sgbackups" \
    -d "$LOG_PATH/stackgres-backup.json" -e '-X POST -w %{http_code} -o /dev/null')"

  if [ "$HTTP_STATUS" = "200" ] || [ "$HTTP_STATUS" = "202" ] || [ "$HTTP_STATUS" = "204" ]
  then
    echo "Request acknowledged by the operator"
    return 0
  else
    ERROR_RESPONSE="$(run_curl -r "stackgres/sgbackups" \
      -d "$LOG_PATH/stackgres-backup.json" -e '-X POST')"
    echo "Invalid response status $HTTP_STATUS. response: $ERROR_RESPONSE"
    return 1
  fi
}

test_api_created_backup_is_visible() {
  create_backup_with_api

  if kubectl get sgbackups.stackgres.io -n "$CLUSTER_NAMESPACE" "$BACKUP_NAME"
  then
    echo "Backup created with the API"
  else
    echo "Backup CR was not created"
    return 1
  fi

  check_backup_directly
}

update_backup_parameter_with_api() {
  local HTTP_STATUS

  UPDATED_STACKGRES_BACKUP="$(cat "$LOG_PATH/stackgres-backup.json" | jq ".spec[\"$1\"] = $2" )"

  echo_raw "$UPDATED_STACKGRES_BACKUP" > "$LOG_PATH/updated-stackgres-backup.json"

  HTTP_STATUS="$(run_curl -r "stackgres/sgbackups" \
    -d "$LOG_PATH/updated-stackgres-backup.json" -e '-X PUT -w %{http_code} -o /dev/null')"

  if [ "$HTTP_STATUS" = "200" ] || [ "$HTTP_STATUS" = "202" ] || [ "$HTTP_STATUS" = "204" ]
  then
    echo "Request acknowledged by the operator"
    return 0
  else
    ERROR_RESPONSE="$(run_curl -r "stackgres/sgbackups" \
      -d "$LOG_PATH/updated-stackgres-backup.json" -e '-X PUT')"
    echo "Invalid response status $HTTP_STATUS. response: $ERROR_RESPONSE"
    return 1
  fi
}

test_api_updated_backup_is_visible() {
  update_backup_parameter_with_api 'managedLifecycle' 'false'

  if kubectl get sgbackups.stackgres.io -n "$CLUSTER_NAMESPACE" "$BACKUP_NAME" \
    -o jsonpath='{.spec.managedLifecycle}' | grep -q "^false$"
  then
    echo "Backup managedLifecycle were false"
  else
    echo "Backup managedLifecycle weren't false"
    return 1
  fi

  if run_curl -r "stackgres/namespaces/$CLUSTER_NAMESPACE/sgbackups/$BACKUP_NAME" | jq '.spec.managedLifecycle' -r \
    | grep -q "^false$"
  then
    echo "Backup updates are being reflected in the api"
  else
    echo "Backup updates aren't being reflected in the api"
    return 1
  fi
}

delete_backup_with_api() {
  local HTTP_STATUS

  HTTP_STATUS="$(run_curl -r "stackgres/sgbackups" \
    -d "$LOG_PATH/stackgres-backup.json" -e '-X DELETE -w %{http_code} -o /dev/null')"

  if [ "$HTTP_STATUS" = "200" ] || [ "$HTTP_STATUS" = "202" ] || [ "$HTTP_STATUS" = "204" ]
  then
    echo "Request acknowledged by the operator"
    return 0
  else
    ERROR_RESPONSE="$(run_curl -r "stackgres/sgbackups" \
      -d "$LOG_PATH/stackgres-backup.json" -e '-X PUT')"
    echo "Invalid response status $HTTP_STATUS. response: $ERROR_RESPONSE"
    return 1
  fi
}

test_api_delete_backup_is_visible() {
  delete_backup_with_api

  if wait_until eval '[ "$(get_backup_http_status)" = "404" ]'
  then
    echo "Backup removed from the API"
  else
    echo "Backup wasn't removed from the API"
    return 1
  fi
}

test_constraint_violation_api_error() {
  INVALID_BACKUP="$(cat "$LOG_PATH/stackgres-backup.json" | jq '.spec.sgCluster = null' )"

  echo "$INVALID_BACKUP" > "$LOG_PATH/invalid-backup.json"

  local HTTP_STATUS

  HTTP_STATUS="$(run_curl -r "stackgres/sgbackups" -n "$CLUSTER_NAMESPACE" \
    -d "$LOG_PATH/invalid-backup.json" -e '-X POST -w %{http_code} -o /dev/null')"

  assert_string_equal "422" "$HTTP_STATUS"

  ERROR_RESPONSE="$(run_curl -r "stackgres/sgbackups" -n "$CLUSTER_NAMESPACE" \
    -d "$LOG_PATH/invalid-backup.json" -e '-X POST')"

  EXPECTED_ERROR_TYPE="constraint-violation"
  EXPECTED_ERROR_TITLE="do not comply with the syntactic rules"
  EXPECTED_ERROR_DETAIL="The cluster name is required"
  EXPECTED_ERROR_FIELD="sgCluster"

  assert_api_error "$ERROR_RESPONSE"

  INVALID_BACKUP_NAME="$(cat "$LOG_PATH/stackgres-backup.json" | jq '.metadata.name = "test-pg12.8"' )"

  echo "$INVALID_BACKUP_NAME" > "$LOG_PATH/invalid-backup-name.json"

  local HTTP_STATUS

  HTTP_STATUS="$(run_curl -r "stackgres/sgbackups" -n "$CLUSTER_NAMESPACE"  -d "$LOG_PATH/invalid-backup-name.json" -e '-X POST -w %{http_code} -o /dev/null')"

  assert_string_equal "422" "$HTTP_STATUS"

  ERROR_RESPONSE="$(run_curl -r "stackgres/sgbackups" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/invalid-backup-name.json" -e '-X POST')"

  EXPECTED_ERROR_TYPE="constraint-violation"
  EXPECTED_ERROR_TITLE="Some fields do not comply with the syntactic rules"
  EXPECTED_ERROR_DETAIL="metadata.name in body should match '^[a-z]([-a-z0-9]*[a-z0-9])?$'"
  EXPECTED_ERROR_FIELD="metadata.name"

  assert_api_error "$ERROR_RESPONSE"
}

test_authentication_api_error() {
  local HTTP_STATUS

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/sgbackups"  -n "$CLUSTER_NAMESPACE" -e "-LI -o /dev/null -w %{http_code}")"

  check_authentication_error

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/namespaces/$CLUSTER_NAMESPACE/sgbackups/$BACKUP_NAME" -n "$CLUSTER_NAMESPACE" -e "-LI -o /dev/null -w %{http_code}")"

  check_authentication_error

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/sgbackups" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/stackgres-backup.json" -e '-X POST -w %{http_code} -o /dev/null')"

  check_authentication_error

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/sgbackups" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/stackgres-backup.json" -e '-X PUT -w %{http_code} -o /dev/null')"

  check_authentication_error

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/sgbackups" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/stackgres-backup.json" -e '-X DELETE -w %{http_code} -o /dev/null')"

  check_authentication_error
}

check_authentication_error() {
  if [ "$HTTP_STATUS" = "401" ]
  then
    echo "Request returned expected authentication error"
    return 0
  else
    echo "Request returned unexpected response status $HTTP_STATUS instead of the expected authentication error."
    return 1
  fi
}

